package socket

import (
	"context"
	gorillaWs "github.com/gorilla/websocket"
	"github.com/kataras/iris/v12/websocket"
	"github.com/kataras/neffos"
	"github.com/kataras/neffos/gorilla"
	"gluenet/pkg/apis"
	"net/http"
	"strings"
	"sync"
)

func MetricsList(c *apis.StorageContext) {
	var metrics []string
	c.MetricsSubscriber.Range(func(key, value interface{}) bool {
		metrics = append(metrics, key.(string))
		return true
	})
	c.WebContext.JSON(apis.ResponseOK(metrics))
}

func MetricsSocket(c *apis.StorageContext) {
	platform := c.WebContext.URLParam("platform")
	metrics := c.WebContext.URLParam("metric")
	guid := c.WebContext.URLParam("guid")
	object := c.WebContext.URLParam("object")
	childstr := c.WebContext.URLParam("childs")
	//guid := c.WebContext.URLParam("guid")
	//kind := c.WebContext.URLParam("kind")

	c.Logger.Debugf("metrics socket")

	childs := strings.Split(childstr, "|")
	var keys = make([]string, len(childs))
	switch object {
	case apis.ObjectMachine:
		for k, child := range childs {
			keys[k] = strings.Join([]string{platform, metrics, guid, child}, "|")
		}
	case apis.ObjectApplication:
		for k, child := range childs {
			keys[k] = strings.Join([]string{platform, metrics, guid, child}, "|")
		}
	}

	ctx, cancel := context.WithCancel(c.Context)
	var ActuallyNodeCpu = websocket.New(gorilla.Upgrader(gorillaWs.Upgrader{
		CheckOrigin: func(*http.Request) bool { return true },
	}), websocket.Events{
		websocket.OnNativeMessage: func(conn *neffos.NSConn, message neffos.Message) error { return nil },
	})

	ActuallyNodeCpu.OnConnect = func(n *websocket.Conn) error {

		//subi, ok := c.Subscriber.Load("kubernetes|container_memory_used_bytes|emojivoto|web-svc")

		for _, key := range keys {
			c.Logger.Debugf("OnConnect from server %v %v", n.ID(), key)
			subi, ok := c.MetricsSubscriber.Load(key)
			if !ok {
				c.Logger.Errorf("metrics not found")
				return nil
			}

			sub := subi.(*sync.Map)
			rchi, _ := sub.LoadOrStore(n.ID(), make(chan string))
			rch := rchi.(chan string)

			go func() {
				for {
					select {
					case data := <-rch:
						n.Write(neffos.Message{
							Body:     []byte(data),
							IsNative: true,
						})
					case <-ctx.Done():
						sub.Delete(n.ID())
						close(rch)
						//c.Logger.Debugf("push down %v", n.ID())
						return
					}
				}
			}()
		}
		<-ctx.Done()
		return nil
	}

	ActuallyNodeCpu.OnDisconnect = func(n *websocket.Conn) {
		cancel()
		c.Logger.Debugf("Disconnected from server", n.ID())
	}

	ActuallyNodeCpu.OnUpgradeError = func(err error) {
		cancel()
		c.Logger.Debugf("OnUpgradeError from server %v", err)
	}

	websocket.Handler(ActuallyNodeCpu)(c.WebContext)
}

func TotalMetricsSocket(c *apis.StorageContext) {
	ctx, cancel := context.WithCancel(c.Context)
	var ActuallyNodeCpu = websocket.New(gorilla.Upgrader(gorillaWs.Upgrader{
		CheckOrigin: func(*http.Request) bool { return true },
	}), websocket.Events{
		websocket.OnNativeMessage: func(conn *neffos.NSConn, message neffos.Message) error { return nil },
	})

	ActuallyNodeCpu.OnConnect = func(n *websocket.Conn) error {
		c.Logger.Debugf("OnConnect from server %v %v", n.ID(), "dd")

		rchi, _ := c.MetricsSubscriberTotal.LoadOrStore(n.ID(), make(chan string))
		rch := rchi.(chan string)

		for {
			select {
			case data := <-rch:
				n.Write(neffos.Message{
					Body:     []byte(data),
					IsNative: true,
				})
			case <-ctx.Done():
				c.MetricsSubscriberTotal.Delete(n.ID())
				close(rch)
				c.Logger.Debugf("push down %v", n.ID())
				return nil
			}
		}
		return nil
	}

	ActuallyNodeCpu.OnDisconnect = func(n *websocket.Conn) {
		cancel()
		c.Logger.Debugf("Disconnected from server", n.ID())
	}

	ActuallyNodeCpu.OnUpgradeError = func(err error) {
		cancel()
		c.Logger.Debugf("OnUpgradeError from server %v", err)
	}

	websocket.Handler(ActuallyNodeCpu)(c.WebContext)
}
